package com.ef.service.impl;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;

import com.ef.constant.EClassEntityType;
import com.ef.constant.EClassType;
import com.ef.constant.ETimeline;
import com.ef.constant.StatusType;
import com.ef.dao.ClassArrangeDao;
import com.ef.domain.ClassEntity;
import com.ef.service.ClassArrangeService;
import com.ef.util.CalendarUtil;
import com.ef.util.CustomExample;
import com.ef.util.PaginationSupport;

public class ClassArrangeServiceImpl extends BaseServiceImpl implements
		ClassArrangeService {

	public ClassArrangeDao getClassArrangeDao() {
		return classArrangeDao;
	}

	public void setClassArrangeDao(ClassArrangeDao classArrangeDao) {
		this.classArrangeDao = classArrangeDao;
	}

	private ClassArrangeDao classArrangeDao;

	public ClassEntity findById(Long id) {
		return classArrangeDao.findById(id);
	}

	public void delete(ClassEntity entity) {
		entity.setStatus(StatusType.INVALID);
		classArrangeDao.update(entity);
	}

	public void saveOrUpdate(ClassEntity entity) {
		classArrangeDao.saveOrUpdate(entity);
	}

	/*
	 * 获取某年某周的排课情况。 按日期以及时间进行了排序.
	 * 
	 * @see com.ef.service.ClassArrangeService#getClassEntity(int, int)
	 */
	public List<ClassEntity> getClassEntity(int year, int week) {
		DetachedCriteria criterion = DetachedCriteria
				.forClass(ClassEntity.class);
		Date monday = CalendarUtil.getMondayOfWeekWithMonDayIsFirstDay(year,
				week);
		Date sunday = CalendarUtil.getSundayOfWeekWithMonDayIsFirstDay(year,
				week);
		criterion.add(Restrictions.ge("classDate", monday));
		criterion.add(Restrictions.le("classDate", sunday));
		criterion.addOrder(Order.desc("classDate"));
		criterion.addOrder(Order.desc("classTime"));
		criterion.add(Restrictions.eq("status", StatusType.VALID));
		return classArrangeDao.findAllByCriteria(criterion);
	}

	public PaginationSupport<ClassEntity> findByExample(
			CustomExample<ClassEntity> example, int startIndex, int pageSize) {
		return classArrangeDao.findPageByExample(example, startIndex, pageSize);
	}

	public List<ClassEntity> getClassEntityByDateTime(Date date,
			ETimeline timeline) {
		DetachedCriteria criterion = DetachedCriteria
				.forClass(ClassEntity.class);
		criterion.add(Restrictions.eq("classDate", date));
		criterion.add(Restrictions.eq("classTime", timeline));
		criterion.add(Restrictions.eq("status", StatusType.VALID));
		return classArrangeDao.findAllByCriteria(criterion);
	}

	public List<ClassEntity> getClassEntityList(Date date) {
		DetachedCriteria criterion = DetachedCriteria
				.forClass(ClassEntity.class);
		criterion.add(Restrictions.eq("classDate", date));
		criterion.add(Restrictions.eq("status", StatusType.VALID));
		criterion.addOrder(Order.asc("classTime"));
		return classArrangeDao.findAllByCriteria(criterion);
	}

	public List<ClassEntity> getClassEntityListByClassEntityType(Date date,
			EClassEntityType classEntityType) {
		DetachedCriteria criterion = DetachedCriteria
				.forClass(ClassEntity.class);
		criterion.add(Restrictions.eq("classDate", date));
		criterion.add(Restrictions.eq("type", classEntityType));
		criterion.add(Restrictions.eq("status", StatusType.VALID));
		criterion.addOrder(Order.asc("classTime"));
		return classArrangeDao.findAllByCriteria(criterion);
	}

	public List<ClassEntity> getClassEntityListByClassEntityType(Date date,
			ArrayList<EClassEntityType> classEntityTypes) {
		DetachedCriteria criterion = DetachedCriteria
				.forClass(ClassEntity.class);
		criterion.add(Restrictions.eq("classDate", date));
		criterion.add(Restrictions.eq("status", StatusType.VALID));
		Disjunction or = Restrictions.disjunction();
		Property myProperty = Property.forName("type");
		for (EClassEntityType type:classEntityTypes){
			or.add(myProperty.eq(type));
		}
		criterion.add(or);
		criterion.addOrder(Order.asc("classTime"));
		return classArrangeDao.findAllByCriteria(criterion);
	}
	
	
	public List<ClassEntity> getClassEntityListByClassType(Date date, EClassType classType) {
		DetachedCriteria criterion = DetachedCriteria
				.forClass(ClassEntity.class);
		criterion.add(Restrictions.eq("classDate", date));
		criterion.createCriteria("classType").add(
				Restrictions.eq("type", classType));
		criterion.add(Restrictions.eq("status", StatusType.VALID));
		criterion.addOrder(Order.asc("classTime"));
		return classArrangeDao.findAllByCriteria(criterion);
	}

	public List<ClassEntity> getClassEntityListByClassType(Date date, ArrayList<EClassType> classTypes) {
		DetachedCriteria criterion = DetachedCriteria
				.forClass(ClassEntity.class);
		criterion.add(Restrictions.eq("classDate", date));
		criterion.add(Restrictions.eq("status", StatusType.VALID));
		Disjunction or = Restrictions.disjunction();
		Property myProperty = Property.forName("type");
		for (EClassType type:classTypes){
			or.add(myProperty.eq(type));
		}
		criterion.createCriteria("classType").add(or);
		criterion.addOrder(Order.asc("classTime"));
		return classArrangeDao.findAllByCriteria(criterion);
	}
	public HashMap<Long, HashMap<String, ClassEntity>> getClassEntityMapInTime(
			Date fDate, Date lDate) {
		DetachedCriteria criterion = DetachedCriteria
				.forClass(ClassEntity.class);
		criterion.add(Restrictions.ge("classDate", fDate));
		criterion.add(Restrictions.le("classDate", lDate));
		criterion.add(Restrictions.eq("status", StatusType.VALID));
		criterion.createAlias("teacher", "teacher");
		criterion.addOrder(Order.asc("teacher.id"));
		List<ClassEntity> classes = classArrangeDao
				.findAllByCriteria(criterion);
		SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
		HashMap<Long, HashMap<String, ClassEntity>> maps = new HashMap<Long, HashMap<String, ClassEntity>>();
		if (classes != null && classes.size() > 0) {
			for (ClassEntity cls : classes) {
				Long teacherid = cls.getTeacher().getId();
				HashMap<String, ClassEntity> tMap = maps.get(teacherid);
				if (tMap == null) {
					tMap = new HashMap<String, ClassEntity>();
					maps.put(teacherid, tMap);
				}
				tMap.put(sd.format(cls.getClassDate())
						+ cls.getClassTime().getName(), cls);
			}
		}
		return maps;
	}

	public ClassEntity getClassEntityByDateTimeAndTeacher(Date date,
			ETimeline timeline, Long teacherid) throws Exception {
		DetachedCriteria criterion = DetachedCriteria
				.forClass(ClassEntity.class);
		criterion.createCriteria("teacher").add(
				Restrictions.eq("id", teacherid));
		criterion.add(Restrictions.eq("classDate", date));
		criterion.add(Restrictions.eq("classTime", timeline));
		criterion.add(Restrictions.eq("status", StatusType.VALID));
		List<ClassEntity> classes = classArrangeDao
				.findAllByCriteria(criterion);
		if (classes == null || classes.size() == 0) {
			return null;
		}
		if (classes.size() == 1) {
			return classes.get(0);
		}
		throw new Exception("At " + date + " " + timeline + " teacherid:"
				+ teacherid + "too many classes");
	}

	public ClassEntity getClassEntityByDateTimeAndClassroom(Date date,
			ETimeline timeline, Long classroomid) throws Exception {
		DetachedCriteria criterion = DetachedCriteria
				.forClass(ClassEntity.class);
		criterion.createCriteria("classroom").add(
				Restrictions.eq("id", classroomid));
		criterion.add(Restrictions.eq("classDate", date));
		criterion.add(Restrictions.eq("classTime", timeline));
		criterion.add(Restrictions.eq("status", StatusType.VALID));
		List<ClassEntity> classes = classArrangeDao
				.findAllByCriteria(criterion);
		if (classes == null || classes.size() == 0) {
			return null;
		}
		if (classes.size() == 1) {
			return classes.get(0);
		}
		throw new Exception("At " + date + " " + timeline + " classroomid:"
				+ classroomid + " too many classes");
	}

	public String getClassCheckMessage(Date date, ETimeline timeline) {
		List<ClassEntity> entitys = getClassEntityByDateTime(date, timeline);
		int all = entitys.size();
		int finish = 0;
		for (ClassEntity entity : entitys) {
			if (entity.getCheckedTimes() > 0) {
				finish++;
			}
		}
		return finish + "/" + all;
	}
}
